using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Configuration;
using System.IO;
using Sio.Mdm.Utils;

namespace Sio.Mdm.Client
{
    /// <summary>
    /// Class for parsing <see cref="Server"/> confgiration. Class is
    /// static because this parsing should be done once per instance.
    /// </summary>
    static class Config
    {
        #region Construction
        static Config()
        {
            //FileSystemWatcher watcher = new FileSystemWatcher(ConfigPath);
            //watcher.Changed += delegate(object sender, FileSystemEventArgs e)
            //{
            //    _servers = null;
            //    ParseConfiguration();
            //};

            //watcher.Filter = Path.GetFileName(ConfigPath);
            //watcher.Path = Path.GetDirectoryName(ConfigPath);
            //watcher.NotifyFilter = NotifyFilters.LastWrite;
            //watcher.EnableRaisingEvents = true;
        }
        #endregion

        #region Properties
        
        #region Public

        #region Servers
        private static List<ServerInformation> _servers;
        /// <summary>
        /// Get list of registered services
        /// </summary>
        public static List<ServerInformation> Servers
        {
            get
            {
                if (null == _servers)
                {
                    ParseConfiguration();
                }

                return _servers;
            }
        }
        #endregion  

        #endregion

        #region Private

        #region ConfigPath
        private static string ConfigPath
        {
            get
            {
                string path = ConfigurationManager.AppSettings["client.config"];

                if (!String.IsNullOrEmpty(path) && !Path.IsPathRooted(path))
                {
                    path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, path);
                }

                return String.IsNullOrEmpty(path)? "client.config": path;
            }
        }
        #endregion

        #endregion

        #endregion

        #region Methods

        #region Private

        #region ParseConfiguration
        /// <summary>
        /// Serach for 'server.confg' file and parse configuration for server from it
        /// </summary>
        private static void ParseConfiguration()
        {
            List<ServerInformation> temporaryServices = new List<ServerInformation>();

            try
            {
                XmlDocument doc = new XmlDocument();

                doc.Load(ConfigPath);

                XmlNode configNode = GetNodeByName(doc, "configuration");

                if ( configNode == null )
                {
                    throw new ArgumentException("Server configuration XML is malformed! Missing configuration node.");
                }
                
                XmlNode serviceNode = GetNodeByName(configNode, "servers");

                foreach (XmlNode node in serviceNode.ChildNodes)
                {
                    // Skip comments
                    if (node is XmlComment)
                    {
                        continue;
                    }
                    
                    // Get service from XML
                    temporaryServices.Add(ServerInformation.FromXML(node.OuterXml));
                }
            }
            catch (Exception ex)
            {
                Logger.WriteError("Config parsing error!");
                Logger.WriteException(ex);
                throw new Exception("Error parsing configuration! See inner excpetion for details.", ex);
            }

            _servers = new List<ServerInformation>(temporaryServices);            
        } 
        #endregion

        #endregion

        #region Internal

        #region GetNodeByName
        internal static XmlNode GetNodeByName(XmlDocument doc, string name)
        {
            foreach (XmlNode node in doc.ChildNodes)
            {
                if (String.Compare(node.Name, name, true) == 0)
                {
                    return node;
                }
            }

            return null;
        }
        internal static XmlNode GetNodeByName(XmlNode parentNode, string name)
        {
            foreach (XmlNode node in parentNode.ChildNodes)
            {
                if (String.Compare(node.Name, name, true) == 0)
                {
                    return node;
                }
            }

            return null;
        }
        #endregion

        #region GetAttributeValueByName
        /// <summary>
        /// Get attribute value and make sure attribute exist
        /// </summary>
        /// <param name="node"></param>
        /// <param name="attributeName"></param>
        /// <returns></returns>
        internal static string GetAttributeValueByName(XmlNode node, string attributeName)
        {
            return node.Attributes[attributeName] == null ?
                String.Empty : node.Attributes[attributeName].Value;
        }
        #endregion

        #endregion

        #endregion
    }
}
